# coding=utf-8

import os

import pexpect
import multiprocessing
from pexpect import *

from app.modules.apps.container_tomcat import TomcatApp
from app.modules.common.pipelines import *
from app.modules.common.tasks import *
from app.modules.common.tasks import TaskExcecuteError, TaskParamsError
from app.modules.database.pipelines import BaseTask

log = logging.getLogger(__name__)

lock = multiprocessing.Lock()


class ImportMysqlPipeLine(Pipeline):
    def __init__(self, name, group = None, timeout = 7200, **kwargs):
        Pipeline.__init__(self, name, group = group, timeout = timeout, **kwargs)

        self.add_task(CheckImportParams())
        self.add_task(CheckMysqlProcessTask())
        self.add_task(CleanTempPathTask())
        self.add_task(CopyDumpFileTask())
        self.add_task(RepairMysql())
        self.add_task(DropMysqlDataBase())
        self.add_task(CreateMysqlDataBase())
        self.add_task(ImportMysqlSchemas())
        self.add_task(ImportMysqlData())
        self.add_task(MysqlAfterImportTask())
        self.add_task(CleanTempPathTask())

    def _before_execute(self):
        log.info('start execute _before_execute')
        self.get_log(log).do_up()
        log.info('end execute _before_execute')

    def _after_execute(self):
        self.get_log(log).do_down()


class CheckImportParams(BaseTask):
    def __init__(self):
        Task.__init__(self, 'CheckImportParams')

    def __do_execute__(self, params = {'username': None,
                                       'password': None,
                                       'temp_path': None,
                                       'dump_path': None,
                                       'db_name': None,
                                       'after_imp_sql_files': None}):
        log_proxy = self.get_log(log)
        log_proxy.info('********************************************************')
        log_proxy.info("=======> CheckImportParams:Entered execute()")

        error_message = []
        param_valid = True
        if not self.param_exists('username', params):
            param_valid = False
            error_message.append('params[username] must not empty')
        else:
            log_proxy.info("=======> params[username] is %s", params['username'])

        if not self.param_exists('password', params):
            param_valid = False
            error_message.append('params[password] must not empty')
        else:
            log_proxy.info("=======> params[password] is %s", params['password'])

        if not self.param_exists('temp_path', params):
            param_valid = False
            error_message.append('params[temp_path] must not empty')
        else:
            log_proxy.info("=======> params[temp_path] is %s", params['temp_path'])

        if not self.param_exists('dump_path', params):
            param_valid = False
            error_message.append('params[dump_path] must not empty')
        else:
            log_proxy.info("=======> params[dump_path] is %s", params['dump_path'])

        if not self.param_exists('db_name', params):
            param_valid = False
            error_message.append('params[db_name] must not empty')
        else:
            log_proxy.info("=======> params[db_name] is %s", params['db_name'])

        if not self.param_exists('after_imp_sql_files', params):
            log_proxy.info("=======> params[after_imp_sql_files] is empty")
        else:
            log_proxy.info("=======> params[after_imp_sql_files] is %s", params['after_imp_sql_files'])

        if not self.param_exists('local_ip', params):
            log_proxy.info("=======> params[local_ip] is empty")
        else:
            log_proxy.info("=======> params[local_ip] is %s", params['local_ip'])

        if param_valid and not os.path.exists(params['dump_path']):
            param_valid = False
            error_message.append('not found dump path[%s].' % params['dump_path'])

        if param_valid and not os.path.exists(params['temp_path']):
            self.create_path(params['temp_path'])

        if not param_valid:
            log_proxy.error("******** %s", error_message)
            raise TaskParamsError(error_message)

        log_proxy.info("=======> CheckImportParams:Exit execute()")


class CheckMysqlProcessTask(Task):
    def __init__(self):
        Task.__init__(self, 'CheckMysqlProcess')

    def __do_execute__(self, params = {}):
        log_proxy = self.get_log(log)
        log_proxy.info('********************************************************')
        log_proxy.info("=======> CheckMysqlProcess:Entered execute()")

        with lock:
            sh = '/bin/bash -c "exit | mysql -u%s -p%s"' % (params['username'], params['password'])

            log_proxy.info('=======> start execute shell : %s', sh)
            try:
                output, status = run(sh, withexitstatus = 1, logfile = log_proxy)
                log_proxy.info('=======> shell status: %s, output: %s', status, output)
            except BaseException, e:
                log_proxy.info('=======> ' + e.message)
                raise TaskExcecuteError('execute shell failure, cause: %s.' % e.message)
            log_proxy.info('=======> end execute shell')

            if status != 0:
                if str(output).find('ERROR 1045') >= 0:
                    log_proxy.info('=======> mysql login failure, username or password error.')
                    raise TaskExcecuteError('username or password error')
                elif str(output).find('Can\'t connect') >= 0:
                    try:
                        mysql = pexpect.spawn('su', timeout = 300)
                        mysql.logfile = log_proxy
                        mysql.expect('$', timeout = 300)
                        log_proxy.info('=======> stop mysql')
                        mysql.sendline('service mysqld stop')
                        mysql.expect('$', timeout = 300)
                        log_proxy.info('=======> startup mysql')
                        mysql.sendline('service mysqld start')
                        mysql.expect('SUCCESS', timeout = 300)
                    except Exception, e:
                        log_proxy.info('=======> ' + e.message)
                        raise TaskExcecuteError('execute shell failure, cause: %s.' % e.message)
                    finally:
                        mysql.close()
                else:
                    log_proxy.info('=======> mysql login failure.')
                    raise TaskExcecuteError('mysql login failure, cause:%s' % output)

            else:
                log_proxy.info('=======> mysql login success.')

            log_proxy.info("=======> CheckMysqlProcess:Exit execute()")


class CleanTempPathTask(BaseTask):

    def __init__(self):
        Task.__init__(self, 'cleanTempPathTask')

    def __do_execute__(self, params = {}):
        log_proxy = self.get_log(log)
        log_proxy.info('********************************************************')
        log_proxy.info("=======> cleanTempPathTask:Entered execute()")

        # 导入uschedule时，先杀掉uschedule进程
        if str(params['db_name']).__contains__('uschedule'):
            log_proxy.info('=======> before import uschedule , kill uschedule')
            killUschedule(str(params['db_name']))

        path = '%s/%s' % (params['temp_path'], params['db_name'])
        self.create_path(path)

        log_proxy.info('********************************************************')
        files_path = '%s/*.gz %s/*.txt %s/*.sql %s/afterimp/*.sql' % (path, path, path, path)

        self.remove_files(files_path)

        log_proxy.info("=======> cleanTempPathTask:Exit execute()")


class CopyDumpFileTask(Task):

    def __init__(self):
        Task.__init__(self, 'CopyDumpFileTask')

    def __do_execute__(self, params = {}):
        log_proxy = self.get_log(log)
        log_proxy.info('********************************************************')
        log_proxy.info("=======> CopyDumpFileTask:Entered execute()")
        path = '%s/%s' % (params['temp_path'], params['db_name'])
        sh = '/bin/bash -c "cp %s/* %s"' % (params['dump_path'], path)

        log_proxy.info('=======> start execute shell : %s', sh)
        try:
            output, status = run(sh, withexitstatus = 1, logfile = log_proxy)
            log_proxy.info('=======> shell status: %s, output: %s', status, output)
        except BaseException, e:
            log_proxy.info('=======> ' + e.message)
            raise TaskExcecuteError('execute shell failure, cause: %s.' % e.message)
        log_proxy.info('=======> end execute shell')

        if status != 0:
            raise TaskExcecuteError('copy dump file failure.')
        else:
            log_proxy.info('=======> copy dump file success.')

        log_proxy.info("=======> CopyDumpFileTask:Exit execute()")


class RepairMysql(Task):

    def __init__(self):
        Task.__init__(self, 'RepairMysql')

    def __do_execute__(self, params = {}):
        log_proxy = self.get_log(log)
        log_proxy.info("=======> RepairMysql:Entered execute()")
        log_proxy.info('********************************************************')

        log_proxy.info('=======> start execute mysql repair')
        try:
            mysql = pexpect.spawn('mysql -u%s -p%s' % (params['username'], params['password']), timeout = 10)
            mysql.logfile = log_proxy
            mysql.expect('mysql>')
            mysql.sendline('REPAIR TABLE mysql.columns_priv;')
            mysql.sendline('REPAIR TABLE mysql.db;')
            mysql.sendline('REPAIR TABLE mysql.event;')
            mysql.sendline('REPAIR TABLE mysql.func;')
            mysql.sendline('REPAIR TABLE mysql.help_category;')
            mysql.sendline('REPAIR TABLE mysql.help_keyword;')
            mysql.sendline('REPAIR TABLE mysql.help_relation;')
            mysql.sendline('REPAIR TABLE mysql.help_topic;')
            mysql.sendline('REPAIR TABLE mysql.host;')
            mysql.sendline('REPAIR TABLE mysql.ndb_binlog_index;')
            mysql.sendline('REPAIR TABLE mysql.plugin;')
            mysql.sendline('REPAIR TABLE mysql.proc;')
            mysql.sendline('REPAIR TABLE mysql.procs_priv;')
            mysql.sendline('REPAIR TABLE mysql.proxies_priv;')
            mysql.sendline('REPAIR TABLE mysql.servers;')
            mysql.sendline('REPAIR TABLE mysql.tables_priv;')
            mysql.sendline('REPAIR TABLE mysql.time_zone;')
            mysql.sendline('REPAIR TABLE mysql.time_zone_leap_second;')
            mysql.sendline('REPAIR TABLE mysql.time_zone_name;')
            mysql.sendline('REPAIR TABLE mysql.time_zone_transition;')
            mysql.sendline('REPAIR TABLE mysql.time_zone_transition_type;')
            mysql.sendline('REPAIR TABLE mysql.user;')
            mysql.sendcontrol('d')
            # log_proxy.info('=======> shell status: %s, output: %s', status, output)
        except BaseException, e:
            log_proxy.info('=======> ' + e.message)
            raise TaskExcecuteError('execute mysql repair failure, cause: %s.' % e.message)
        log_proxy.info('=======> execute mysql repair success')

        # if status != 0:
        #     raise TaskExcecuteError('copy dump file failure.')
        # else:
        #     log_proxy.info('=======> copy dump file success.')

        log_proxy.info("=======> RepairMysql:Exit execute()")


class DropMysqlDataBase(Task):

    def __init__(self):
        Task.__init__(self, 'DropMysqlDataBase')

    def __do_execute__(self, params = {}):
        log_proxy = self.get_log(log)
        log_proxy.info('********************************************************')
        log_proxy.info("=======> DropMysqlDataBase:Entered execute()")

        db_name = params['db_name']
        log_proxy.info('=======> start drop database: %s', db_name)
        try:
            mysql = pexpect.spawn('mysql -u%s -p%s' % (params['username'], params['password']), timeout = 30)
            mysql.logfile = log_proxy
            mysql.expect('mysql>')
            mysql.sendline('drop database if exists %s;' % db_name)
            index = mysql.expect(['Query OK(.*)', pexpect.EOF], timeout = None)

            if index == 0:
                log_proxy.info('=======> drop mysql database success')
            elif index == 1:
                log_proxy.info('drop mysql database failure.')
                raise TaskExcecuteError('drop mysql database failure.')

            mysql.sendcontrol('d')
        except BaseException, e:
            log_proxy.info('=======> ' + e.message)
            raise TaskExcecuteError('drop mysql database failure, cause: %s.' % e.message)

        log_proxy.info("=======> DropMysqlDataBase:Exit execute()")


class CreateMysqlDataBase(Task):

    def __init__(self):
        Task.__init__(self, 'CreateMysqlDataBase')

    def __do_execute__(self, params = {}):
        log_proxy = self.get_log(log)
        log_proxy.info('********************************************************')
        log_proxy.info("=======> CreateMysqlDataBase:Entered execute()")

        db_name = params['db_name']
        log_proxy.info('=======> start create database: %s DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci', db_name)
        try:
            mysql = pexpect.spawn('mysql -u%s -p%s' % (params['username'], params['password']), timeout = 30)
            mysql.logfile = log_proxy
            mysql.expect('mysql>')
            mysql.sendline('create database %s DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;' % db_name)
            index = mysql.expect('Query OK(.*)')
            mysql.sendcontrol('d')

            # log_proxy.info('=======> shell index: %s', index)

        except Exception, e:
            log_proxy.info('=======> ' + e.message)
            raise TaskExcecuteError('create mysql database failure, cause: %s.' % e.message)
        mysql.close()
        log_proxy.info('=======> create mysql database success')
        log_proxy.info("=======> CreateMysqlDataBase:Exit execute()")


class ImportMysqlSchemas(Task):

    def __init__(self):
        Task.__init__(self, 'ImportMysqlDataBase')

    def __do_execute__(self, params = {}):
        log_proxy = self.get_log(log)
        log_proxy.info('********************************************************')
        log_proxy.info("=======> ImportMysqlDataBase:Entered execute()")

        db_name = params['db_name']
        log_proxy.info('=======> start import mysql schema : %s', db_name)
        try:
            username = params['username']
            password = params['password']
            db_name = params['db_name']
            scheme_file = '%s/%s/%s.schema.sql' % (params['temp_path'], db_name, db_name)
            sh = '/bin/bash -c "mysql -u%s -p%s %s < %s"' % (username, password, db_name, scheme_file)
            log_proxy.info('start execute shell : %s', sh)
            output, status = pexpect.run(sh, withexitstatus = 1, timeout = 600, logfile = log_proxy)

            log_proxy.info('=======> shell status: %s, output: %s', status, output)

            if status == 0:
                log_proxy.info('=======> import mysql schema success')
            else:
                raise TaskExcecuteError('import mysql schema failure, cause: %s.' % output)

        except Exception, e:
            log_proxy.info('=======> ' + e.message)
            raise TaskExcecuteError('import mysql schema failure.')
        log_proxy.info("=======> ImportMysqlDataBase:Exit execute()")


class ImportMysqlData(Task):

    def __init__(self):
        Task.__init__(self, 'ImportMysqlData')

    def __do_execute__(self, params = {}):
        log_proxy = self.get_log(log)
        log_proxy.info('********************************************************')
        log_proxy.info("=======> ImportMysqlData:Entered execute()")

        db_name = params['db_name']
        log_proxy.info('=======> start import mysql data: %s', db_name)
        try:
            username = params['username']
            password = params['password']
            db_name = params['db_name']
            data_path = params['temp_path'] + '/' + params['db_name']

            for file in os.listdir(data_path):
                if file.endswith('.sql.gz'):
                    log_proxy.info("======> start import %s", file)
                    data_file = data_path + '/' + file
                    sh = '/bin/bash -c "zcat %s | mysql -u%s -p%s %s 2>&1;"' % (data_file, username, password, db_name)

                    log_proxy.info('start execute shell : %s', sh)
                    output, status = pexpect.run(sh, withexitstatus = 1, timeout = None, logfile = log_proxy)
                    log_proxy.info('=======> shell status: %s, output: %s', status, output)

                    if status == 0:
                        log_proxy.info('=======> import mysql data success')
                    else:
                        raise TaskExcecuteError('import mysql data failure, cause: %s.' % output)
        except Exception, e:
            log_proxy.info('=======> ' + e.message)
            raise TaskExcecuteError('import mysql data failure.')
        log_proxy.info("=======> ImportMysqlData:Exit execute()")


class MysqlAfterImportTask(Task):

    def __init__(self):
        Task.__init__(self, 'MysqlAfterImportTask')

    def __replace_keyword__(self, params, temp_path, filename):
        log_proxy = self.get_log(log)
        if os.path.isfile(filename):
            log_proxy.info('=====> start replace and copy import after sql file[%s]', filename)
            db_name = params['db_name']
            local_ip = params['local_ip']
            log_proxy.info('=====> local ipaddress: [%s]', local_ip)
            new_filename = temp_path + '/' + os.path.basename(filename)
            tbs = open(filename)
            lines = tbs.readlines()
            fp = open(new_filename, 'w')
            for line in lines:
                if line.find('${dbname}') >= 0:
                    line = line.replace('${dbname}', db_name)
                if line.find('$localIp') >= 0:
                    line = line.replace('$localIp', local_ip)
                fp.write(line)
            fp.close()
            tbs.close()
            log_proxy.info('=====> end replace and copy import after sql file')
            return new_filename
        else:
            return None

    def __do_execute__(self, params = {}):
        log_proxy = self.get_log(log)
        log_proxy.info('********************************************************')
        log_proxy.info("=======> MysqlAfterImportTask:Entered execute()")

        username = params['username']
        password = params['password']
        db_name = params['db_name']
        log_proxy.info('=======> start mysql data clean : %s', db_name)
        try:
            temp_path = '%s/%s/afterimp' % (params['temp_path'], params['db_name'])
            sh = 'mkdir -p %s' % temp_path
            log_proxy.info('start execute shell : %s', sh)
            output, status = pexpect.run(sh, withexitstatus = 1, timeout = 30, logfile = log_proxy)
            log_proxy.info('=======> shell status: %s, output: %s', status, output)
            if status != 0:
                raise TaskExcecuteError('create dir[%s] failure, cause: %s.' % (temp_path, output))

            if 'after_imp_sql_files' in params.keys():
                after_imp_sql_files = params['after_imp_sql_files']
                if after_imp_sql_files and len(after_imp_sql_files) > 0:
                    for sql_file in after_imp_sql_files:
                        sql_file = self.__replace_keyword__(params, temp_path, sql_file)
                        if sql_file:
                            sh = '/bin/bash -c "mysql -u%s -p%s %s < %s"' % (username, password, db_name, sql_file)
                            log_proxy.info('start execute shell : %s', sh)
                            output, status = pexpect.run(sh, withexitstatus = 1, timeout = 3600, logfile = log_proxy)

                            log_proxy.info('=======> shell status: %s, output: %s', status, output)

                            if status == 0:
                                log_proxy.info('=======> mysql after import success')
                            else:
                                raise TaskExcecuteError('mysql after import failure, cause: %s.' % output)
                        else:
                            log_proxy.info('=======> after the introduction of the import of the script does not exist')
            else:
                log_proxy.info('=======> after the introduction of the import of the script does not exist')

        except Exception, e:
            log_proxy.info('=======> ' + e.message)
            raise TaskExcecuteError('Mysql database after the introduction of the import of the script failure.')
        log_proxy.info("=======> MysqlAfterImportTask:Exit execute()")


def killUschedule(db_name):
    try:
        if 'uschedule' == db_name:
            tomcat = TomcatApp(app_id = 'gzidc:uschedule',
                               app_name = 'uschedule',
                               zone_home_path = '/usr/local/app/uc.gzidc.area',
                               zone_alias = 'gzidc',
                               port = '380',
                               nas_app_package_path = ''
                               )
        elif 'uschedule_au' == db_name:
            tomcat = TomcatApp(app_id = 'auaws:uschedule',
                               app_name = 'uschedule',
                               zone_home_path = '/usr/local/app/uc.auaws.area',
                               zone_alias = 'auaws',
                               port = '30380',
                               nas_app_package_path = ''
                               )
        elif 'uschedule_eu' == db_name:
            tomcat = TomcatApp(app_id = 'euaws:uschedule',
                               app_name = 'uschedule',
                               zone_home_path = '/usr/local/app/uc.euaws.area',
                               zone_alias = 'euaws',
                               port = '20380',
                               nas_app_package_path = ''
                               )
        elif 'uschedule_us' == db_name:
            tomcat = TomcatApp(app_id = 'usaws:uschedule',
                               app_name = 'uschedule',
                               zone_home_path = '/usr/local/app/uc.usaws.area',
                               zone_alias = 'usaws',
                               port = '10380',
                               nas_app_package_path = ''
                               )

        tomcat.stop()
    except BaseException, ex:
        print traceback.format_exc()
